package com.example.cleverz.service;

import cn.hutool.core.map.MapUtil;
import com.example.cleverz.service.utils.AuthUtils;
import com.nimbusds.oauth2.sdk.TokenRequest;
import com.nimbusds.oauth2.sdk.auth.verifier.InvalidClientException;
import lombok.AllArgsConstructor;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.ReactiveAuthenticationManager;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextImpl;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.client.registration.InMemoryReactiveClientRegistrationRepository;
import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.web.server.authentication.ServerFormLoginAuthenticationConverter;
import org.springframework.security.web.server.context.ServerSecurityContextRepository;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.UUID;

@RestController
@AllArgsConstructor
public class LoginController {

    private final ReactiveAuthenticationManager authenticationManager;
    private final ServerSecurityContextRepository contextRepository;

    private final PasswordEncoder passwordEncoder;

    private static final String BASIC_ = "Basic ";


    @PostMapping("/login")
    public Mono login(ServerWebExchange exchange) {
        return new ServerFormLoginAuthenticationConverter().convert(exchange)
                .flatMap(authentication -> authenticationManager.authenticate(authentication)
                        .doOnSuccess(auth -> {
                            contextRepository
                                    .save(exchange, new SecurityContextImpl(auth))
                                    .then(Mono.defer(() -> {
                                        final ServerHttpRequest request = exchange.getRequest();

                                        // 追加token信息和其他信息
                                        System.out.println("追加信息");



                                        String header = Objects.requireNonNull(request.getHeaders().get(HttpHeaders.AUTHORIZATION)).get(0);

                                        if (header == null || !header.startsWith(BASIC_)) {
                                            throw new BadCredentialsException("请求头中client信息为空");
                                        }

                                        return clientRegistrations().findByRegistrationId("client_1")
                                                .flatMap(clientDetails -> {
                                                    String[] tokens = AuthUtils.extractAndDecodeHeader(header);
                                                    assert tokens.length == 2;
                                                    String clientId = tokens[0];
                                                    //校验secret
                                                    if (!passwordEncoder.matches(tokens[1], clientDetails.getClientSecret())) {
                                                        authentication.setAuthenticated(true);
                                                    }

                                                    return exchange.getFormData().map(stringStringMultiValueMap -> {
                                                        return stringStringMultiValueMap.getFirst("grant_type");
                                                    }).map(grantType -> {
                                                        TokenRequest tokenRequest = new TokenRequest(MapUtil.newHashMap(), clientId, clientDetails.getScopes(), grantType);

                                                    })

                                                });

                                        final String token = UUID.randomUUID().toString().replaceAll("-", "");
                                        return Mono.just(token);
                                    }));
                        })
                        .doOnError(throwable -> {
                            System.out.println("错误的登录");
                            throw new BadCredentialsException("不给通过");
                        })
                );
    }


    private ReactiveClientRegistrationRepository clientRegistrations() {
        System.out.println("Load client Registration Repository");
        return new InMemoryReactiveClientRegistrationRepository(Arrays.asList(
                ClientRegistration.withRegistrationId("web")
                        .clientId("web")
                        .clientName("web")
                        .clientSecret("123456")
                        .tokenUri("/user/token_1")
                        .authorizationGrantType(AuthorizationGrantType.PASSWORD)
                        .build(),
                ClientRegistration.withRegistrationId("app")
                        .clientId("app")
                        .clientName("app")
                        .clientSecret("123456")
                        .tokenUri("/user/token_2")
                        .authorizationGrantType(AuthorizationGrantType.PASSWORD)
                        .build(),
                ClientRegistration.withRegistrationId("applet")
                        .clientId("applet")
                        .clientName("applet")
                        .clientSecret("123456")
                        .tokenUri("/user/token_3")
                        .authorizationGrantType(AuthorizationGrantType.PASSWORD)
                        .build()
        ));
    }
}
